// 
// Copyright (c) 2006-2009 Ben Motmans
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// Author(s):
//    Ben Motmans <ben.motmans@gmail.com>
//

using System;
using System.Collections;
using System.Collections.Generic;

namespace Anculus.Core
{
	/// <summary>
	/// 
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class SortedCollection<T> : ICollection<T> where T : IComparable<T>
	{
		protected List<T> list;
		protected SortOrder sortOrder;

		/// <summary>
		/// Initializes a new instance of the <see cref="SortedCollection&lt;T&gt;"/> class.
		/// </summary>
		public SortedCollection ()
			: this (SortOrder.Ascending)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SortedCollection&lt;T&gt;"/> class.
		/// </summary>
		/// <param name="capacity">The capacity.</param>
		public SortedCollection (int capacity)
			: this (SortOrder.Ascending, capacity)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SortedCollection&lt;T&gt;"/> class.
		/// </summary>
		/// <param name="sortOrder">The sort order.</param>
		public SortedCollection (SortOrder sortOrder)
		{
			this.list = new List<T> ();
			this.sortOrder = sortOrder;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SortedCollection&lt;T&gt;"/> class.
		/// </summary>
		/// <param name="sortOrder">The sort order.</param>
		/// <param name="capacity">The capacity.</param>
		public SortedCollection (SortOrder sortOrder, int capacity)
		{
			if (capacity < 0)
				throw new ArgumentOutOfRangeException ("capacity");
			
			this.sortOrder = sortOrder;
			this.list = new List<T> (capacity);
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SortedCollection&lt;T&gt;"/> class.
		/// </summary>
		/// <param name="enumerable">The enumerable.</param>
		public SortedCollection (IEnumerable<T> enumerable)
			: this ()
		{
			if (enumerable == null)
				throw new ArgumentNullException ("enumerable");
			
			list = new List<T> ();
			foreach (T item in enumerable)
				Add (item);
		}

		/// <summary>
		/// Gets or sets the sort order.
		/// </summary>
		/// <value>The sort order.</value>
		public SortOrder SortOrder
		{
			get { return sortOrder; }
			set {
				if (sortOrder != value) {
					sortOrder = value;
					Sort.QuickSort<T> (list, sortOrder);
				}
			}
		}

		/// <summary>
		/// Gets the number of items in the collection.
		/// </summary>
		/// <value>The number of items in the collection.</value>
		public int Count
		{
			get { return list.Count; }
		}

		/// <summary>
		/// Indicates whether this instance is read only.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is read only; otherwise, <c>false</c>.
		/// </value>
		public bool IsReadOnly
		{
			get { return false; }
		}

		/// <summary>
		/// Gets the <see cref="T"/> at the specified index.
		/// </summary>
		/// <value></value>
		public T this [int index]
		{
			get { return list[index]; }
		}

		/// <summary>
		/// Adds the specified item.
		/// </summary>
		/// <param name="item">The item.</param>
		public void Add (T item)
		{
			if (item == null)
				throw new ArgumentNullException ("item");
			
			Insert.SortedInsert<T> (list, sortOrder, item);
		}

		/// <summary>
		/// Adds the range.
		/// </summary>
		/// <param name="items">The items.</param>
		public void AddRange (IEnumerable<T> items)
		{
			foreach (T item in items)
				Add (item);
		}

		/// <summary>
		/// Removes the specified item.
		/// </summary>
		/// <param name="item">The item.</param>
		/// <returns></returns>
		public bool Remove (T item)
		{
			if (item == null)
				throw new ArgumentNullException ("item");
			
			return list.Remove (item);
		}

		/// <summary>
		/// Determines whether the collection contains the specified item.
		/// </summary>
		/// <param name="item">The item.</param>
		/// <returns>
		/// 	<c>true</c> if the collection contains the specified item.; otherwise, <c>false</c>.
		/// </returns>
		public bool Contains (T item)
		{
			if (item == null)
				throw new ArgumentNullException ("item");
			
			return list.BinarySearch (item) >= 0;
		}

		/// <summary>
		/// Clears the collection.
		/// </summary>
		public void Clear ()
		{
			list.Clear ();
		}

		/// <summary>
		/// Copies to.
		/// </summary>
		/// <param name="array">The array.</param>
		/// <param name="arrayIndex">Index of the array.</param>
		public void CopyTo (T[] array, int arrayIndex)
		{
			list.CopyTo (array, arrayIndex);
		}

		/// <summary>
		/// Gets the enumerator.
		/// </summary>
		/// <returns></returns>
		public IEnumerator<T> GetEnumerator ()
		{
			return list.GetEnumerator ();
		}

		/// <summary>
		/// Returns an enumerator that iterates through a collection.
		/// </summary>
		/// <returns>
		/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
		/// </returns>
		IEnumerator IEnumerable.GetEnumerator ()
		{
			return ((IEnumerable)list).GetEnumerator ();
		}
	}
}
